package frame

import (
	"crypto/rand"
	"fmt"
	"math/big"
	"net"
	"os"
	"path/filepath"
	"reflect"
	"strings"

	"github.com/gin-gonic/gin"
)

type RoutePath struct {
	Method string
	Path   string
}

// 给指定结构体注册路由
func RegRouteStruct(r *gin.Engine, su any, group string) {
	// 创建路由组
	Rgroup := r.Group(group)

	// 获取中间件
	middlewareArr := []gin.HandlerFunc{}
	if middleware := GetMiddleware(su); middleware != nil {
		middlewareArr = middleware
	}

	// 获取支持的HTTP方法
	methodArr := []string{}
	if methods := GetMethodSlice(su); methods != nil {
		methodArr = methods
	}

	// 获取结构体的方法名
	methodNames := GetMethodNames(su)

	// 为每个方法注册路由
	for _, method := range methodNames {
		// 创建处理函数链：中间件 + 方法调用
		handlers := append(middlewareArr, func(c *gin.Context) {
			success, err := CallMethodByName(su, method, c)
			if !success {
				c.AbortWithStatusJSON(500, gin.H{
					"code": 500,
					"msg":  err.Error(),
				})
				return
			}
		})

		// 把url请求都转小写
		methodLower := strings.ToLower(method)

		if len(methodArr) <= 0 {
			Rgroup.Any("/"+methodLower, handlers...)
		} else {
			// 为所有支持的HTTP方法注册路由
			for _, httpMethod := range methodArr {
				HandleMethods(Rgroup, []string{httpMethod}, "/"+methodLower, handlers...)
			}
		}

	}
}

func GetMethodNames(s interface{}) []string {
	t := reflect.TypeOf(s)
	if t.Kind() == reflect.Ptr {
		t = t.Elem()
	}

	var methods []string
	for i := 0; i < t.NumMethod(); i++ {
		methods = append(methods, t.Method(i).Name)
	}

	return methods
}

// 通过方法名调用结构体的方法
func CallMethodByName(st any, methodName string, c *gin.Context) (bool, error) {
	// 获取反射值
	val := reflect.ValueOf(st)

	// 获取方法
	method := val.MethodByName(methodName)
	if !method.IsValid() {
		return false, fmt.Errorf("方法 %s 不存在", methodName)
	}

	// 准备参数
	args := []reflect.Value{reflect.ValueOf(c)}

	// 调用方法
	method.Call(args)

	return true, nil
}

func HandleMethods(r *gin.RouterGroup, methods []string, path string, handlers ...gin.HandlerFunc) {
	for _, method := range methods {
		lower_method := strings.ToUpper(method)
		r.Handle(lower_method, path, handlers...)
	}
}

// 使用反射检查 su 是否有 Method_ 字段，并且是 []string 类型
func GetMethodSlice(su any) []string {
	v := reflect.ValueOf(su)

	// 如果 su 是指针，解引用
	if v.Kind() == reflect.Ptr {
		v = v.Elem()
	}

	// 检查 su 是否是结构体
	if v.Kind() != reflect.Struct {
		return nil
	}

	// 检查是否有 Method_ 字段
	field := v.FieldByName("Method_")
	if !field.IsValid() {
		return nil
	}

	// 检查 Method_ 是否是 []string
	if field.Kind() == reflect.Slice && field.Type().Elem().Kind() == reflect.String {
		return field.Interface().([]string)
	}

	return nil
}

// 使用反射检查 su 是否有 Middleware_ 字段，并且是 []gin.HandlerFunc{} 类型
func GetMiddleware(su any) []gin.HandlerFunc {
	v := reflect.ValueOf(su)

	// 如果 su 是指针，解引用
	if v.Kind() == reflect.Ptr {
		v = v.Elem()
	}

	// 检查 su 是否是结构体
	if v.Kind() != reflect.Struct {
		return nil
	}

	// 检查是否有 Method_ 字段
	field := v.FieldByName("Middleware_")
	if !field.IsValid() {
		return nil
	}

	// 检查 Middleware_ 是否是 []gin.HandlerFunc{}
	if field.Kind() == reflect.Slice {
		// 获取 gin.HandlerFunc 的类型
		handlerFuncType := reflect.TypeOf((gin.HandlerFunc)(nil))

		// 检查切片元素类型是否匹配 gin.HandlerFunc
		if field.Type().Elem() == handlerFuncType {
			// 安全转换
			if field.CanInterface() {
				return field.Interface().([]gin.HandlerFunc)
			}
		}
	}

	return nil
}

// 判断字符串是否在字符串切片中
func Contains(filter []string, s string) bool {
	for _, item := range filter {
		// 因为转路由的时候是进行转小写了所以这里也要转一下
		if strings.ToLower(item) == s {
			return true
		}
	}
	return false
}

// 获取本地局域网IP
func GetLocalIP() (string, error) {
	interfaces, err := net.Interfaces()
	if err != nil {
		return "", err
	}

	for _, iface := range interfaces {
		// 跳过非活跃接口和回环接口
		if iface.Flags&net.FlagUp == 0 || iface.Flags&net.FlagLoopback != 0 {
			continue
		}

		addrs, err := iface.Addrs()
		if err != nil {
			continue
		}

		for _, addr := range addrs {
			ipNet, ok := addr.(*net.IPNet)
			if !ok {
				continue
			}
			ip := ipNet.IP
			// 筛选 IPv4 地址（非回环、非多播）
			if ip.To4() != nil && !ip.IsLoopback() && !ip.IsMulticast() {
				return ip.String(), nil
			}
		}
	}

	return "", fmt.Errorf("no valid LAN IP found")
}

// RandomString 生成包含大小写字母和数字的随机字符串
// length: 需要生成的字符串长度
func RandomString(length int) (string, error) {
	const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
	result := make([]byte, length)

	for i := 0; i < length; i++ {
		// 生成一个随机索引
		n, err := rand.Int(rand.Reader, big.NewInt(int64(len(charset))))
		if err != nil {
			return "", fmt.Errorf("[方块互联]日志含义生成随机数失败: %v", err)
		}
		result[i] = charset[n.Int64()]
	}

	return string(result), nil
}

// 判断文件是否存在
func FileExists(path string) bool {
	_, err := os.Stat(path)
	if err == nil {
		return true
	}
	if os.IsNotExist(err) {
		return false
	}
	// 其他类型的错误（如权限问题）
	return false
}

// EnsureDirectoryExists 确保指定路径的目录存在
// 参数可以是目录路径或文件路径，如果是文件路径会自动解析其所在目录
func EnsureDirectoryExists(path string) error {
	// 获取路径的目录部分（如果是文件路径会自动提取目录）
	dir := filepath.Dir(path)

	// 检查目录是否存在
	if _, err := os.Stat(dir); os.IsNotExist(err) {
		// 创建目录（包括所有必要的父目录）
		if err := os.MkdirAll(dir, 0755); err != nil {
			return fmt.Errorf("创建目录失败 %q: %v", dir, err)
		}
	} else if err != nil {
		// 其他类型的错误（如权限问题）
		return fmt.Errorf("检查目录失败 %q: %v", dir, err)
	}

	return nil
}
